package com.hzhc.utils;


import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 根据ip离线查询地址
 *
 * @author ruoyi
 */
public class RegionUtil {
	private static final Logger log = LoggerFactory.getLogger(RegionUtil.class);

	private static final String JAVA_TEMP_DIR = "java.io.tmpdir";

	static DbConfig config = null;
	static DbSearcher searcher = null;

	// 初始化IP库
	static {
		try {
			// 因为jar无法读取文件,复制创建临时文件
			String dbPath = Objects.requireNonNull(RegionUtil.class.getResource("/ip2region/ip2region.db")).getPath();
			File file = new File(dbPath);
			if (!file.exists()) {
				String tmpDir = System.getProperties().getProperty(JAVA_TEMP_DIR);
				dbPath = tmpDir + "ip2region.db";
				file = new File(dbPath);
				ClassPathResource cpr = new ClassPathResource("ip2region" + File.separator + "ip2region.db");
				InputStream resourceAsStream = cpr.getInputStream();
				FileUtils.copyInputStreamToFile(resourceAsStream, file);
			}
			config = new DbConfig();
			searcher = new DbSearcher(config, dbPath);
			log.info("bean [{}]", config);
			log.info("bean [{}]", searcher);
		} catch (Exception e) {
			log.error("init ip region error:{}", e.toString());
		}
	}

	/**
	 * 解析IP
	 *
	 * @param ip
	 * @return
	 */
	public static String getRegion(String ip) {
		try {
			// db
			if (searcher == null || StringUtils.isEmpty(ip)) {
				log.error("DbSearcher is null");
				return StringUtils.EMPTY;
			}
			long startTime = System.currentTimeMillis();
			// 查询算法
			Method method = searcher.getClass().getMethod("memorySearch", String.class);

			DataBlock dataBlock = null;
			if (!Util.isIpAddress(ip)) {
				log.warn("warning: Invalid ip address");
			}
			dataBlock = (DataBlock) method.invoke(searcher, ip);
			String result = dataBlock.getRegion();
			long endTime = System.currentTimeMillis();
			log.debug("region use time[{}] result[{}]", endTime - startTime, result);
			return result;

		} catch (Exception e) {
			log.error("error:{}", e.toString());
		}
		return StringUtils.EMPTY;
	}


	// 未知地址
	public static final String UNKNOWN = "未知地址";

	public static String getRealAddress(String ip) {
		// 内网不查询
		if (internalIp(ip)) {
			return "内网IP";
		}
		try {
			String rspStr = RegionUtil.getRegion(ip);
			if (StringUtils.isNotEmpty(rspStr)) {
				String[] obj = rspStr.split("\\|");
				String region = obj[2];
				String city = obj[3];

				return String.format("%s%s", region, city);
			}
		} catch (Exception e) {
			log.error("获取地理位置异常 {}", e.toString());
		}
		// ali地域查询
		return PureNetUtils.getAlibaba(ip);
	}

	/* 判断是否是内网IP */
	public static boolean internalIp(String ipAddress) {
		boolean isInnerIp = false;
		long ipNum = getIpNum(ipAddress);
		/*
		 * 私有IP：A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类
		 * 192.168.0.0-192.168.255.255 当然，还有127这个网段是环回地址
		 */
		long aBegin = getIpNum("10.0.0.0");
		long aEnd = getIpNum("10.255.255.255");
		long bBegin = getIpNum("172.16.0.0");
		long bEnd = getIpNum("172.31.255.255");
		long cBegin = getIpNum("192.168.0.0");
		long cEnd = getIpNum("192.168.255.255");
		isInnerIp = isInner(ipNum, aBegin, aEnd)
				|| isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)
				|| ipAddress.equals("127.0.0.1");
		return isInnerIp;
	}

	/* 获取IP数 */
	private static long getIpNum(String ipAddress) {
		String[] ip = ipAddress.split("\\.");
		long a = Integer.parseInt(ip[0]);
		long b = Integer.parseInt(ip[1]);
		long c = Integer.parseInt(ip[2]);
		long d = Integer.parseInt(ip[3]);
		return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
	}

	private static boolean isInner(long userIp, long begin, long end) {
		return (userIp >= begin) && (userIp <= end);
	}

//	public static void main(String[] args) {
//		String realAddress = getRealAddress("117.136.79.113");
//		System.out.println("realAddress = " + realAddress);
//	}
}